﻿using System;
using System.Collections.Concurrent;
using System.Collections.ObjectModel;

namespace uTrade.Core
{
    /// <summary>
    ///
    /// </summary>
    public class DataSeries : Collection<double>
    {
        private static readonly ConcurrentDictionary<Tuple<DataSeries, DataSeries>, DataSeries> _dicOperateAdd = new ConcurrentDictionary<Tuple<DataSeries, DataSeries>, DataSeries>();
        private static readonly ConcurrentDictionary<Tuple<DataSeries, DataSeries>, DataSeries> _dicOperateSub = new ConcurrentDictionary<Tuple<DataSeries, DataSeries>, DataSeries>();
        private static readonly ConcurrentDictionary<Tuple<DataSeries, DataSeries>, DataSeries> _dicOperateMul = new ConcurrentDictionary<Tuple<DataSeries, DataSeries>, DataSeries>();
        private static readonly ConcurrentDictionary<Tuple<DataSeries, DataSeries>, DataSeries> _dicOperateDiv = new ConcurrentDictionary<Tuple<DataSeries, DataSeries>, DataSeries>();
        private static readonly ConcurrentDictionary<Tuple<DataSeries, DataSeries>, DataSeries> _dicOperateMod = new ConcurrentDictionary<Tuple<DataSeries, DataSeries>, DataSeries>();

        private readonly DataSeries _base = null;
        private CollectionChange _onChanging;
        private CollectionChange _onChanged;

        /// <summary>
        /// 构建函数(参数勿填)
        /// </summary>
        /// <param name="baseSeries">同步序列</param>
        public DataSeries(DataSeries baseSeries = null)
        {
            if (baseSeries == null)
            {
                return;
            }

            _base = baseSeries;
            //初始时同步
            foreach (var v in _base)
            {
                this.Add(v);
            }
            _base.OnChanging += Base_OnChanging;
        }

        /// <summary>
        /// 无效时返回Nan
        /// </summary>
        /// <param name="index">从0开始计数</param>
        /// <returns>无效时返回Nan</returns>
        public new double this[int index]
        {
            get
            {
                double rtn = double.NaN;
                if (Count - 1 - index >= 0)
                {
                    rtn = base[Count - 1 - index];
                }
                return rtn;
            }
            set
            {
                if (Count - 1 - index < 0)
                {
                    return;
                }
                base[Count - 1 - index] = value;
            }
        }

        #region 函数

        /// <summary>
        /// 取指定范围的最大值
        /// </summary>
        /// <param name="begin"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public double Highest(int begin, int length)
        {
            double rtn = double.MinValue;
            for (int i = begin; i < begin + length && i < Count; i++)
            {
                rtn = Math.Max(rtn, this[i]);
            }
            return rtn;
        }

        /// <summary>
        /// 取指定范围的最小值
        /// </summary>
        /// <param name="begin"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public double Lowest(int begin, int length)
        {
            double rtn = double.MaxValue;
            for (int i = begin; i < begin + length && i < Count; i++)
            {
                rtn = Math.Min(rtn, this[i]);
            }
            return rtn;
        }

        /// <summary>
        /// 取指定范围的和
        /// </summary>
        /// <param name="begin"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public double Sum(int begin, int length)
        {
            double rtn = 0;
            for (int i = begin; i < begin + length && i < Count; i++)
            {
                rtn += this[i];
            }
            return rtn;
        }

        /// <summary>
        /// 取指定范围的均值
        /// </summary>
        /// <param name="begin"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public double Average(int begin, int length)
        {
            double rtn = 0;
            for (int i = begin; i < begin + length && i < Count; i++)
            {
                rtn += this[i];
            }
            return rtn / length;
        }

        #endregion 函数

        private void Base_OnChanging(int pType, object pNew, object pOld)
        {
            if (pType == 1) //增加
            {
                this.Add((double)pNew);
            }
        }

        /// <summary>
        /// 策略变化:加1;减-1;更新0
        /// </summary>
        public event CollectionChange OnChanging
        {
            add
            {
                _onChanging += value;
            }
            remove
            {
                _onChanging -= value;
            }
        }

        /// <summary>
        ///
        /// </summary>
        public event CollectionChange OnChanged
        {
            add
            {
                _onChanged += value;
            }
            remove
            {
                _onChanged -= value;
            }
        }

        /// <summary>
        /// 在指定位置处插入值
        /// </summary>
        /// <param name="index"></param>
        /// <param name="item"></param>
        protected override void InsertItem(int index, double item)
        {
            base.InsertItem(index, item);
            _onChanging?.Invoke(1, item, null);
            _onChanged?.Invoke(1, item, null);
        }

        /// <summary>
        /// 设置指定位置的值
        /// </summary>
        /// <param name="index"></param>
        /// <param name="item"></param>
        protected override void SetItem(int index, double item)
        {
            base.SetItem(index, item);
            _onChanging?.Invoke(0, item, base[index]);
            _onChanged?.Invoke(0, item, base[index]);
        }

        /// <summary>
        /// 两个序列中各值相加(两序列数目必须相等)
        /// </summary>
        /// <param name="s1"></param>
        /// <param name="s2"></param>
        /// <returns></returns>
        public static DataSeries operator +(DataSeries s1, DataSeries s2)
        {
            if (s1.Count != s2.Count)
            {
                return null;
            }
            DataSeries ds = null;
            foreach (var v in _dicOperateAdd)
            {
                if (v.Key.Item1 == s1 && v.Key.Item2 == s2)
                {
                    ds = v.Value;
                    break;
                }
            }
            if (ds == null)
            {
                ds = new DataSeries();
                _dicOperateAdd[new Tuple<DataSeries, DataSeries>(s1, s2)] = ds;
            }
            //更新
            if (ds.Count == s1.Count)
            {
                ds[0] = s1[0] + s2[0];
            }
            else//添加
            {
                for (int i = ds.Count; i < s1.Count; i++)
                {
                    ds.Add(s1.Items[i] + s2.Items[i]);
                }
            }

            return ds;
        }

        /// <summary>
        /// 两个序列中各值相减(两序列数目必须相等)
        /// </summary>
        /// <param name="s1"></param>
        /// <param name="s2"></param>
        /// <returns></returns>
        public static DataSeries operator -(DataSeries s1, DataSeries s2)
        {
            if (s1.Count != s2.Count)
            {
                return null;
            }
            DataSeries ds = null;
            foreach (var v in _dicOperateSub)
            {
                if (v.Key.Item1 == s1 && v.Key.Item2 == s2)
                {
                    ds = v.Value;
                    break;
                }
            }
            if (ds == null)
            {
                ds = new DataSeries();
                _dicOperateSub[new Tuple<DataSeries, DataSeries>(s1, s2)] = ds;
            }
            //更新
            if (ds.Count == s1.Count)
            {
                ds[0] = s1[0] - s2[0];
            }
            else//添加
            {
                for (int i = ds.Count; i < s1.Count; i++)
                {
                    ds.Add(s1.Items[i] - s2.Items[i]);
                }
            }

            return ds;
        }

        /// <summary>
        /// 两个序列中各值相加(两序列数目必须相等)
        /// </summary>
        /// <param name="s1"></param>
        /// <param name="s2"></param>
        /// <returns></returns>
        public static DataSeries operator *(DataSeries s1, DataSeries s2)
        {
            if (s1.Count != s2.Count)
            {
                return null;
            }
            DataSeries ds = null;
            foreach (var v in _dicOperateMul)
            {
                if (v.Key.Item1 == s1 && v.Key.Item2 == s2)
                {
                    ds = v.Value;
                    break;
                }
            }
            if (ds == null)
            {
                ds = new DataSeries();
                _dicOperateMul[new Tuple<DataSeries, DataSeries>(s1, s2)] = ds;
            }
            //更新
            if (ds.Count == s1.Count)
            {
                ds[0] = s1[0] * s2[0];
            }
            else//添加
            {
                for (int i = ds.Count; i < s1.Count; i++)
                {
                    ds.Add(s1.Items[i] * s2.Items[i]);
                }
            }

            return ds;
        }

        /// <summary>
        /// 两个序列中各值相除(两序列数目必须相等)
        /// </summary>
        /// <param name="s1"></param>
        /// <param name="s2"></param>
        /// <returns></returns>
        public static DataSeries operator /(DataSeries s1, DataSeries s2)
        {
            if (s1.Count != s2.Count)
            {
                return null;
            }
            DataSeries ds = null;
            foreach (var v in _dicOperateDiv)
            {
                if (v.Key.Item1 == s1 && v.Key.Item2 == s2)
                {
                    ds = v.Value;
                    break;
                }
            }
            if (ds == null)
            {
                ds = new DataSeries();
                _dicOperateDiv[new Tuple<DataSeries, DataSeries>(s1, s2)] = ds;
            }
            //更新
            if (ds.Count == s1.Count)
            {
                ds[0] = s1[0] / s2[0];
            }
            else//添加
            {
                for (int i = ds.Count; i < s1.Count; i++)
                {
                    ds.Add(s1.Items[i] / s2.Items[i]);
                }
            }

            return ds;
        }

        /// <summary>
        /// 两个序列中各值相余(两序列数目必须相等)
        /// </summary>
        /// <param name="s1"></param>
        /// <param name="s2"></param>
        /// <returns></returns>
        public static DataSeries operator %(DataSeries s1, DataSeries s2)
        {
            if (s1.Count != s2.Count)
            {
                return null;
            }

            DataSeries ds = null;
            foreach (var v in _dicOperateMod)
            {
                if (v.Key.Item1 == s1 && v.Key.Item2 == s2)
                {
                    ds = v.Value;
                    break;
                }
            }
            if (ds == null)
            {
                ds = new DataSeries();
                _dicOperateMod[new Tuple<DataSeries, DataSeries>(s1, s2)] = ds;
            }
            //更新
            if (ds.Count == s1.Count)
            {
                ds[0] = s1[0] % s2[0];
            }
            else//添加
            {
                for (int i = ds.Count; i < s1.Count; i++)
                {
                    ds.Add(s1.Items[i] % s2.Items[i]);
                }
            }

            return ds;
        }
    }
}